package blackstar.performance;

import java.text.NumberFormat;
import java.util.logging.Logger;

import blackstar.performance.logger.MessageBuilder;
import blackstar.performance.logger.RollingFileLogger;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class InvokePerformance extends PerformanceStat implements
		InvokePerformanceMBean
{
	private final static Logger LOGGER = Logger
			.getLogger(InvokePerformance.class.getSimpleName());

	public final static String BEAN_NAME = "name=Simple,type=InvokePerformance";
	public final static String CLASS_NAME = InvokePerformance.class.getName()
			.replace('.', '/');
	public final static String INVOKE_METHOD = "invokeMethod";
	public final static String METHOD_SYNTAX = "(Ljava/lang/String;Ljava/lang/String;J)V";

	private static RollingFileLogger rollingFileLogger;

	private static boolean appendTime = false;// 是否输出时间信息
	private final static boolean stat;
	static
	{
		String isStat = System.getProperty("statperm");
		stat = !("false".equalsIgnoreCase(isStat));
		LOGGER.info("state:" + stat + ";appendTime:" + appendTime);
	}
	private static long totalInvokes = 0L;
	private static long totalPerfTimeNano = 0L;
	private static final Object LOCK = new Object();

	public static boolean isStat()
	{
		return InvokePerformance.stat;
	}

	public static long getTotalInvokes()
	{
		return InvokePerformance.totalInvokes;
	}

	public static long getTotalPerfTimeNano()
	{
		return InvokePerformance.totalPerfTimeNano;
	}

	public static void init(RollingFileLogger rollingFileLogger, 
			long bufferSize, boolean appendTime)
	{
		InvokePerformance.rollingFileLogger = rollingFileLogger;
		InvokePerformance.appendTime = appendTime;
		if (InvokePerformance.isStat())
		{
			InvokePerformance invokePerformance = new InvokePerformance();
			invokePerformance.setBufferSize(bufferSize);
			rollingFileLogger.setLogStat(invokePerformance);
			MBeanRegister.registMBean(BEAN_NAME, invokePerformance);
		}
	}

	public static void invokeMethod(String className, String methodName,
			long timeNano)
	{
		if (InvokePerformance.stat)
		{
			long time = System.nanoTime();
			doInvokeMethod(className, methodName, timeNano);
			time = System.nanoTime() - time;
			synchronized (LOCK)
			{
				InvokePerformance.totalPerfTimeNano += time;
				InvokePerformance.totalInvokes++;
			}
		} else
		{
			doInvokeMethod(className, methodName, timeNano);
		}
	}

	private static void doInvokeMethod(String className, String methodName,
			long timeNano)
	{
		try
		{
			MessageBuilder builder = new MessageBuilder();
			builder.append(className);
			builder.appendSplit();
			builder.append(methodName);
			builder.appendSplit();
			builder.append(timeNano);
			if (InvokePerformance.appendTime)
			{
				builder.appendSplit();
				builder.appendTimestamp();
			}
			builder.appendLineSep();
			rollingFileLogger.log(builder.getMessage());
		} catch (Exception e)
		{
			LOGGER.info("error do log:" + e.getMessage());
		}
	}

	public long getInvokes()
	{
		return InvokePerformance.totalInvokes;
	}

	public long getPerfTimeNano()
	{
		return InvokePerformance.totalPerfTimeNano;
	}

	private final static long MILLISECONDS = 1000000L;

	public String getInvokeMessage()
	{
		long invokes = InvokePerformance.totalInvokes;
		long timePerfNano = InvokePerformance.totalPerfTimeNano;

		NumberFormat timeFormat = NumberFormat.getNumberInstance();
		timeFormat.setMaximumFractionDigits(3);

		StringBuilder message = new StringBuilder();
		message.append("Invokes=");
		message.append(invokes);
		message.append(", PerfTimes=");
		message.append(timeFormat
				.format(((double) timePerfNano) / MILLISECONDS));
		message.append("ms");
		message.append(", AvarageTimes=");
		if (invokes == 0)
		{
			message.append("?");
		}
		else
		{
			message.append(timeFormat.format(((double) timePerfNano) / invokes));
		}
		message.append("ns");

		return message.toString();
	}
}